<?php
class Shell_Command_Ls extends Shell_Command_Abstract_PathCompletionCommand implements Shell_Command_Abstract_IShellCommand
{
	
	/** 
	 * Array, contains the maximum length of each of $fs_items['info'] properties. 
	 * Needed for formatting the columns when printing out the directory listings. 
	 */
	private $maxLengths_files;
	private $maxLengths_dirs;
	
//*************************************************************************************************
	public function __construct()
	{
		parent::__construct();
		$this->NAME = "ls";

		// define the command line options for the command
		$rules = array( 
						'all|a' => 'Show hidden files and folders, i.e. do not ignore entries starting with . ',
						'h' => 'Print sizes in human readable format. (e.g., 1K, 234M, 2G, etc.)',
						'l' => 'Long format, displaying size, date, filename, etc.',
		 
						
					  );
					  		
		$this->options->addRules( $rules );
	}
	
//*************************************************************************************************
	public function execute($arguments) 
	{		
		
		parent::execute($arguments);
		
		// try to parse the command line options, terminate command's execution if options were incorrect
		if ( $this->parseOptions() === false )
			return;
				
		//echo "\n\n a-option:" .  $this->options->getOption('a') . "\n\n";	
		$options = array();	
		$options['a'] = $this->options->getOption('a');
		$options['h'] = $this->options->getOption('h');
		$options['l'] = $this->options->getOption('l');
			
		
		
		$args = $this->options->getRemainingArgs(); 			
		$this->listDirectory($args, $options);
	}	
	
//*************************************************************************************************
	private function listDirectory($args, $options)
	{
		$path = "";
		if ( count($args)>0 )
		$path = $args[0];
	
		$fs = Core_Registry::read(Enum_RegistryItems::FILE_SYSTEM);	
		$dirContent = $fs->readDir($path, $options);		

		if($dirContent['files'] === null)
		{
			echo "\n" . $dirContent['dir_path'] . ' ' . $dirContent['msg']."\n";
			
			// completePath() should return a boolean, indicating if a user could choose something suitable or not.
			
			//$this->completePath( $dirContent['dir_path'] );
			return; 
		}
		
		$files = $dirContent['files'];
		$dirs = $dirContent['dirs'];
		$dirPath = $dirContent['dir_path'];
		
		$this->maxLengths_files = $this->findMaxLengths($files);
		$this->maxLengths_dirs = $this->findMaxLengths($dirs);
				
		// TODO: add flags for sorting options and use the following 2 lines as well. 
		//sort($dirs,SORT_STRING);
		//sort($files,SORT_STRING);

		
		
		$result = " Listing of $dirPath ";
		$result = "\n\n" . Core_StringUtils::underline($result, '=');		
		$result.= "\n\n DIR:\n\t";
		$result.= $this->makeRecords($dirs, $options, false);
		
		$result.= "\n\n FILE:\n\t";
		$result.= $this->makeRecords($files, $options, true);		
		$result.="\n\n";
		echo $result;

	}
	
//***************************************************************************************************
	private function makeRecords($fs_items, $options, $isRecordFile)
	{
		$result = "";
		
				
		foreach ($fs_items as $item) 
		{
			$record = "\n  ";
			$name = $item['name'];
			$info = $item['info'];
			
			// skip the hidden files if option -a was not provided
			if ($name[0] == '.' && !$options['a'])
				continue;
			
			// check if long format is required
			if( $options['l'])
			{
				$record.= $this->makeTime($info['mtime']); 
			}
			
			if ($isRecordFile)
			{					
				$record.= $this->makeSize($info, $options['h'], $this->maxLengths_files['size']);
			}
				
			$record.= ' ' . $name;
			$result.= $record;			
		}
		
		return $result;
	}

//***************************************************************************************************
	private function findMaxLengths($fs_items)
	{
		
		// initialize $maxes array with zeros.
		$maxes = array();
		foreach ($fs_items[0]['info'] as $key => $value)
		{
			$maxes[$key] = 0;
		}
		//print_r($maxes);
		
		// find maximum value of each info element and save it to $maxes with a corresponding key
		$maxLen = 0;
		foreach ($fs_items as $item) 
		{	
			foreach ($item['info'] as $key => $value)
			{
				if (strlen($value)+2 > $maxes[$key]) 
					$maxes[$key] = strlen($value)+2;
			}
		}		
		//print_r($maxes);
		return $maxes;
	}
	
	
	 

//***************************************************************************************************
	private function makeTime($timestamp)
	{
		$maxLength = strlen("2007 Apr 25  13:24:19");
		$time = date("Y M d  H:i:s", $timestamp); 
		
		/*while ( strlen($time)< $maxLength )
		{
			$time = ' '.$time ;
		}*/
		return $time;
		//'2006 May'
	}
	 
//***************************************************************************************************
	private function makeSize($info, $humanReadable, $maxLength)
	{
			$size = $info['size'];
			

			if ($humanReadable)
			{			
				$units = array('', 'K', 'M', 'G', 'T');
				for ($i = 0; $size > 1024; $i++)
				{
					$size /= 1024; 
				}			
				$size = round($size, 2).$units[$i]; 
			}
			
			while ( strlen($size)< $maxLength )
			{
				$size = ' '.$size ;
			}
			
			
			
			return $size;
	}
	
/*
Keys in $maxLengths_files and $maxLengths_dirs:	

0	dev		device number
1	ino		inode number *
2	mode	inode protection mode
3	nlink	number of links
4	uid		userid of owner *
5	gid		groupid of owner *
6	rdev	device type, if inode device
7	size	size in bytes
8	atime	time of last access (Unix timestamp)
9	mtime	time of last modification (Unix timestamp)
10	ctime	time of last inode change (Unix timestamp)
11	blksize	blocksize of filesystem IO **
12	blocks	number of 512-byte blocks allocated **
*/	
	
}